package com.margo.project.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.logout.LogoutFilter;

import com.margo.project.security.util.MD5Util;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MargoWebSecurityConfig extends WebSecurityConfigurerAdapter {
	// Spring会自动寻找同样类型的具体类注入，这里就是JwtUserDetailsServiceImpl了
	@Autowired
	MargoUserDetailsService margoUserDetailsService;
	// 登录成功处理类，如返回自定义jwt
	@Autowired
	MargoAuthenticationSuccessHandler margoAuthenticationSuccessHandler;
	// 登录失败处理类
	@Autowired
	MargoAuthenticationFailHandler margoAuthenticationFailHandler;
	// token 过滤器，解析token
	@Autowired
	MargoJwtTokenFilter margoJwtTokenFilter;
	// 权限不足处理类
	@Autowired
	MargoAccessDeniedHandler margoccessDeniedHandler;
	// 其他异常处理类
	@Autowired
	MargoAuthenticationException margoAuthenticationException;

//	@Autowired
//	public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
//		authenticationManagerBuilder
//				// 设置UserDetailsService 获取user对象
//				.userDetailsService(this.margoUserDetailsService)
//				// 自定义密码验证方法
//				.passwordEncoder(new PasswordEncoder() {
//					// 这个方法没用
//					@Override
//					public String encode(CharSequence charSequence) {
//						return "";
//					}
//
//					// 自定义密码验证方法,charSequence:用户输入的密码，s:我们查出来的数据库密码
//					@Override
//					public boolean matches(CharSequence charSequence, String s) {
//						String pass = MD5Util.string2MD5(charSequence.toString());
//						System.out.println("用户输入密码:" + charSequence + "与数据库相同？" + s.equals(pass));
//						return s.equals(pass);
//					}
//				});
//
//	}

	@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}

	@Override
	protected void configure(HttpSecurity httpSecurity) throws Exception {
		httpSecurity.
		// 指定登录的地址，用户登录请求必须是表单格式，application/json方式是接受不到参数的
		// 这样写参数可以 http://localhost:8080/user/login?username=admin&password=123456
				formLogin().loginProcessingUrl("/user/login")
//                .failureForwardUrl("/test/error") //这个没效果
				.successHandler(margoAuthenticationSuccessHandler)
				.failureHandler(margoAuthenticationFailHandler).and()
				// 由于使用的是JWT，我们这里不需要csrf
				.csrf().disable()
				// 基于token，所以不需要session
				.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
				// .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
				.antMatchers("/user/login", "/admin/register")// 对登录注册要允许匿名访问
				.permitAll()
				// 允许对于网站静态资源的无授权访问
				.antMatchers(HttpMethod.GET, "/", "/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js")
				.permitAll()
				// 除上面外的所有请求全部需要鉴权认证
				.anyRequest().authenticated();

		// 禁用缓存
		httpSecurity.headers().cacheControl();

		// 添加JWT filter
		httpSecurity.addFilterBefore(margoJwtTokenFilter, LogoutFilter.class)
				// 添加权限不足 filter
				.exceptionHandling().accessDeniedHandler(margoccessDeniedHandler)
				// 其他异常处理类
				.authenticationEntryPoint(margoAuthenticationException);

	}
}
